home *** CD-ROM | disk | FTP | other *** search
/ Your Choice 1 / your choice.zip / your choice / PRGMMING / DFLT18 / EDITBOX.C < prev    next >
Text File  |  1994-02-01  |  35KB  |  1,105 lines

  1. /* ------------- editbox.c ------------ */
  2. #include "dflat.h"
  3.  
  4. #define EditBufLen(wnd) (isMultiLine(wnd) ? EDITLEN : ENTRYLEN)
  5. #define SetLinePointer(wnd, ln) (wnd->CurrLine = ln)
  6. #define Ch(c) ((c)&0x7f)
  7. #define isWhite(c) (Ch(c)==' '||Ch(c)=='\n'||Ch(c)=='\f'||Ch(c)=='\t')
  8. /* ---------- local prototypes ----------- */
  9. static void SaveDeletedText(WINDOW, char *, int);
  10. static void Forward(WINDOW);
  11. static void Backward(WINDOW);
  12. static void End(WINDOW);
  13. static void Home(WINDOW);
  14. static void Downward(WINDOW);
  15. static void Upward(WINDOW);
  16. static void StickEnd(WINDOW);
  17. static void NextWord(WINDOW);
  18. static void PrevWord(WINDOW);
  19. static void ModTextPointers(WINDOW, int, int);
  20. static void SetAnchor(WINDOW, int, int);
  21. /* -------- local variables -------- */
  22. static BOOL KeyBoardMarking, ButtonDown;
  23. static BOOL TextMarking;
  24. static int ButtonX, ButtonY;
  25. static int PrevY = -1;
  26.  
  27. /* ----------- CREATE_WINDOW Message ---------- */
  28. static int CreateWindowMsg(WINDOW wnd)
  29. {
  30.     int rtn = BaseWndProc(EDITBOX, wnd, CREATE_WINDOW, 0, 0);
  31.     wnd->MaxTextLength = MAXTEXTLEN+1;
  32.     wnd->textlen = EditBufLen(wnd);
  33.     wnd->InsertMode = TRUE;
  34.     SendMessage(wnd, CLEARTEXT, 0, 0);
  35.     return rtn;
  36. }
  37. /* ----------- SETTEXT Message ---------- */
  38. static int SetTextMsg(WINDOW wnd, PARAM p1)
  39. {
  40.     int rtn = FALSE;
  41.     if (strlen((char *)p1) <= wnd->MaxTextLength)    {
  42.         rtn = BaseWndProc(EDITBOX, wnd, SETTEXT, p1, 0);
  43.         wnd->TextChanged = FALSE;
  44.     }
  45.     return rtn;
  46. }
  47. /* ----------- CLEARTEXT Message ------------ */
  48. static int ClearTextMsg(WINDOW wnd)
  49. {
  50.     int rtn = BaseWndProc(EDITBOX, wnd, CLEARTEXT, 0, 0);
  51.     unsigned blen = EditBufLen(wnd)+2;
  52.     wnd->text = DFrealloc(wnd->text, blen);
  53.     memset(wnd->text, 0, blen);
  54.     wnd->wlines = 0;
  55.     wnd->CurrLine = 0;
  56.     wnd->CurrCol = 0;
  57.     wnd->WndRow = 0;
  58.     wnd->wleft = 0;
  59.     wnd->wtop = 0;
  60.     wnd->textwidth = 0;
  61.     wnd->TextChanged = FALSE;
  62.     return rtn;
  63. }
  64. /* ----------- ADDTEXT Message ---------- */
  65. static int AddTextMsg(WINDOW wnd, PARAM p1, PARAM p2)
  66. {
  67.     int rtn = FALSE;
  68.     if (strlen((char *)p1)+wnd->textlen <= wnd->MaxTextLength) {
  69.         rtn = BaseWndProc(EDITBOX, wnd, ADDTEXT, p1, p2);
  70.         if (rtn != FALSE)    {
  71.             if (!isMultiLine(wnd))    {
  72.                 wnd->CurrLine = 0;
  73.                 wnd->CurrCol = strlen((char *)p1);
  74.                 if (wnd->CurrCol >= ClientWidth(wnd))    {
  75.                     wnd->wleft = wnd->CurrCol-ClientWidth(wnd);
  76.                     wnd->CurrCol -= wnd->wleft;
  77.                 }
  78.                 wnd->BlkEndCol = wnd->CurrCol;
  79.                 SendMessage(wnd, KEYBOARD_CURSOR,
  80.                                      WndCol, wnd->WndRow);
  81.             }
  82.         }
  83.     }
  84.     return rtn;
  85. }
  86. /* ----------- GETTEXT Message ---------- */
  87. static int GetTextMsg(WINDOW wnd, PARAM p1, PARAM p2)
  88. {
  89.     char *cp1 = (char *)p1;
  90.     char *cp2 = wnd->text;
  91.     if (cp2 != NULL)    {
  92.         while (p2-- && *cp2 && *cp2 != '\n')
  93.             *cp1++ = *cp2++;
  94.         *cp1 = '\0';
  95.         return TRUE;
  96.     }
  97.     return FALSE;
  98. }
  99. /* ----------- SETTEXTLENGTH Message ---------- */
  100. static int SetTextLengthMsg(WINDOW wnd, unsigned int len)
  101. {
  102.     if (++len < MAXTEXTLEN)    {
  103.         wnd->MaxTextLength = len;
  104.         if (len < wnd->textlen)    {
  105.             wnd->text=DFrealloc(wnd->text, len+2);
  106.             wnd->textlen = len;
  107.             *((wnd->text)+len) = '\0';
  108.             *((wnd->text)+len+1) = '\0';
  109.             BuildTextPointers(wnd);
  110.         }
  111.         return TRUE;
  112.     }
  113.     return FALSE;
  114. }
  115. /* ----------- KEYBOARD_CURSOR Message ---------- */
  116. static void KeyboardCursorMsg(WINDOW wnd, PARAM p1, PARAM p2)
  117. {
  118.     wnd->CurrCol = (int)p1 + wnd->wleft;
  119.     wnd->WndRow = (int)p2;
  120.     wnd->CurrLine = (int)p2 + wnd->wtop;
  121.     if (wnd == inFocus)    {
  122.         if (CharInView(wnd, (int)p1, (int)p2))
  123.             SendMessage(NULL, SHOW_CURSOR,
  124.                 (wnd->InsertMode && !TextMarking), 0);
  125.         else
  126.             SendMessage(NULL, HIDE_CURSOR, 0, 0);
  127.     }
  128. }
  129. /* ----------- SIZE Message ---------- */
  130. int SizeMsg(WINDOW wnd, PARAM p1, PARAM p2)
  131. {
  132.     int rtn = BaseWndProc(EDITBOX, wnd, SIZE, p1, p2);
  133.     if (WndCol > ClientWidth(wnd)-1)
  134.         wnd->CurrCol = ClientWidth(wnd)-1 + wnd->wleft;
  135.     if (wnd->WndRow > ClientHeight(wnd)-1)    {
  136.         wnd->WndRow = ClientHeight(wnd)-1;
  137.         SetLinePointer(wnd, wnd->WndRow+wnd->wtop);
  138.     }
  139.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  140.     return rtn;
  141. }
  142. /* ----------- SCROLL Message ---------- */
  143. static int ScrollMsg(WINDOW wnd, PARAM p1)
  144. {
  145.     int rtn = FALSE;
  146.     if (isMultiLine(wnd))    {
  147.         rtn = BaseWndProc(EDITBOX,wnd,SCROLL,p1,0);
  148.         if (rtn != FALSE)    {
  149.             if (p1)    {
  150.                 /* -------- scrolling up --------- */
  151.                 if (wnd->WndRow == 0)    {
  152.                     wnd->CurrLine++;
  153.                     StickEnd(wnd);
  154.                 }
  155.                 else
  156.                     --wnd->WndRow;
  157.             }
  158.             else    {
  159.                 /* -------- scrolling down --------- */
  160.                 if (wnd->WndRow == ClientHeight(wnd)-1)    {
  161.                     if (wnd->CurrLine > 0)
  162.                         --wnd->CurrLine;
  163.                     StickEnd(wnd);
  164.                 }
  165.                 else
  166.                     wnd->WndRow++;
  167.             }
  168.             SendMessage(wnd,KEYBOARD_CURSOR,WndCol,wnd->WndRow);
  169.         }
  170.     }
  171.     return rtn;
  172. }
  173. /* ----------- HORIZSCROLL Message ---------- */
  174. static int HorizScrollMsg(WINDOW wnd, PARAM p1)
  175. {
  176.     int rtn = FALSE;
  177.     char *currchar = CurrChar;
  178.     if (!(p1 &&
  179.             wnd->CurrCol == wnd->wleft && *currchar == '\n'))  {
  180.         rtn = BaseWndProc(EDITBOX, wnd, HORIZSCROLL, p1, 0);
  181.         if (rtn != FALSE)    {
  182.             if (wnd->CurrCol < wnd->wleft)
  183.                 wnd->CurrCol++;
  184.             else if (WndCol == ClientWidth(wnd))
  185.                 --wnd->CurrCol;
  186.             SendMessage(wnd,KEYBOARD_CURSOR,WndCol,wnd->WndRow);
  187.         }
  188.     }
  189.     return rtn;
  190. }
  191. /* ----------- SCROLLPAGE Message ---------- */
  192. static int ScrollPageMsg(WINDOW wnd, PARAM p1)
  193. {
  194.     int rtn = FALSE;
  195.     if (isMultiLine(wnd))    {
  196.         rtn = BaseWndProc(EDITBOX, wnd, SCROLLPAGE, p1, 0);
  197.         SetLinePointer(wnd, wnd->wtop+wnd->WndRow);
  198.         StickEnd(wnd);
  199.         SendMessage(wnd, KEYBOARD_CURSOR,WndCol, wnd->WndRow);
  200.     }
  201.     return rtn;
  202. }
  203. /* ----------- HORIZSCROLLPAGE Message ---------- */
  204. static int HorizPageMsg(WINDOW wnd, PARAM p1)
  205. {
  206.     int rtn = BaseWndProc(EDITBOX, wnd, HORIZPAGE, p1, 0);
  207.     if ((int) p1 == FALSE)    {
  208.         if (wnd->CurrCol > wnd->wleft+ClientWidth(wnd)-1)
  209.             wnd->CurrCol = wnd->wleft+ClientWidth(wnd)-1;
  210.     }
  211.     else if (wnd->CurrCol < wnd->wleft)
  212.         wnd->CurrCol = wnd->wleft;
  213.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  214.     return rtn;
  215. }
  216. /* ----- Extend the marked block to the new x,y position ---- */
  217. static void ExtendBlock(WINDOW wnd, int x, int y)
  218. {
  219.     int bbl, bel;
  220.     int ptop = min(wnd->BlkBegLine, wnd->BlkEndLine);
  221.     int pbot = max(wnd->BlkBegLine, wnd->BlkEndLine);
  222.     char *lp = TextLine(wnd, wnd->wtop+y);
  223.     int len = (int) (strchr(lp, '\n') - lp);
  224.     x = max(0, min(x, len));
  225.     y = max(0, y);
  226.     wnd->BlkEndCol = min(len, x+wnd->wleft);
  227.     wnd->BlkEndLine = y+wnd->wtop;
  228.     bbl = min(wnd->BlkBegLine, wnd->BlkEndLine);
  229.     bel = max(wnd->BlkBegLine, wnd->BlkEndLine);
  230.     while (ptop < bbl)    {
  231.         WriteTextLine(wnd, NULL, ptop, FALSE);
  232.         ptop++;
  233.     }
  234.     for (y = bbl; y <= bel; y++)
  235.         WriteTextLine(wnd, NULL, y, FALSE);
  236.     while (pbot > bel)    {
  237.         WriteTextLine(wnd, NULL, pbot, FALSE);
  238.         --pbot;
  239.     }
  240. }
  241. /* ----------- LEFT_BUTTON Message ---------- */
  242. static int LeftButtonMsg(WINDOW wnd, PARAM p1, PARAM p2)
  243. {
  244.     int MouseX = (int) p1 - GetClientLeft(wnd);
  245.     int MouseY = (int) p2 - GetClientTop(wnd);
  246.     RECT rc = ClientRect(wnd);
  247.     char *lp;
  248.     int len;
  249.     if (KeyBoardMarking)
  250.         return TRUE;
  251.     if (WindowMoving || WindowSizing)
  252.         return FALSE;
  253.     if (isMultiLine(wnd))    {
  254.         if (TextMarking)    {
  255.             if (!InsideRect(p1, p2, rc))    {
  256.                 int x = MouseX, y = MouseY;
  257.                 int dir;
  258.                 MESSAGE msg = 0;
  259.                 if ((int)p2 == GetTop(wnd))
  260.                     y++, dir = FALSE, msg = SCROLL;
  261.                 else if ((int)p2 == GetBottom(wnd))
  262.                     --y, dir = TRUE, msg = SCROLL;
  263.                 else if ((int)p1 == GetLeft(wnd))
  264.                     --x, dir = FALSE, msg = HORIZSCROLL;
  265.                 else if ((int)p1 == GetRight(wnd))
  266.                     x++, dir = TRUE, msg = HORIZSCROLL;
  267.                 if (msg != 0)    {
  268.                     if (SendMessage(wnd, msg, dir, 0))
  269.                         ExtendBlock(wnd, x, y);
  270.                     SendMessage(wnd, PAINT, 0, 0);
  271.                 }
  272.             }
  273.             return TRUE;
  274.         }
  275.         if (!InsideRect(p1, p2, rc))
  276.             return FALSE;
  277.         if (TextBlockMarked(wnd))    {
  278.             ClearTextBlock(wnd);
  279.             SendMessage(wnd, PAINT, 0, 0);
  280.         }
  281.         if (wnd->wlines)    {
  282.             if (MouseY > wnd->wlines-1)
  283.                 return TRUE;
  284.             lp = TextLine(wnd, MouseY+wnd->wtop);
  285.             len = (int) (strchr(lp, '\n') - lp);
  286.             MouseX = min(MouseX, len);
  287.             if (MouseX < wnd->wleft)    {
  288.                 MouseX = 0;
  289.                 SendMessage(wnd, KEYBOARD, HOME, 0);
  290.             }
  291.             ButtonDown = TRUE;
  292.             ButtonX = MouseX;
  293.             ButtonY = MouseY;
  294.         }
  295.         else
  296.             MouseX = MouseY = 0;
  297.         wnd->WndRow = MouseY;
  298.         SetLinePointer(wnd, MouseY+wnd->wtop);
  299.     }
  300.     if (isMultiLine(wnd) ||
  301.         (!TextBlockMarked(wnd)
  302.             && MouseX+wnd->wleft < strlen(wnd->text)))
  303.         wnd->CurrCol = MouseX+wnd->wleft;
  304.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  305.     return TRUE;
  306. }
  307. /* ----------- MOUSE_MOVED Message ---------- */
  308. static int MouseMovedMsg(WINDOW wnd, PARAM p1, PARAM p2)
  309. {
  310.     int MouseX = (int) p1 - GetClientLeft(wnd);
  311.     int MouseY = (int) p2 - GetClientTop(wnd);
  312.     RECT rc = ClientRect(wnd);
  313.     if (!InsideRect(p1, p2, rc))
  314.         return FALSE;
  315.     if (MouseY > wnd->wlines-1)
  316.         return FALSE;
  317.     if (ButtonDown)    {
  318.         SetAnchor(wnd, ButtonX+wnd->wleft, ButtonY+wnd->wtop);
  319.         TextMarking = TRUE;
  320.         rc = WindowRect(wnd);
  321.         SendMessage(NULL,MOUSE_TRAVEL,(PARAM) &rc, 0);
  322.         ButtonDown = FALSE;
  323.     }
  324.     if (TextMarking && !(WindowMoving || WindowSizing))    {
  325.         ExtendBlock(wnd, MouseX, MouseY);
  326.         return TRUE;
  327.     }
  328.     return FALSE;
  329. }
  330. static void StopMarking(WINDOW wnd)
  331. {
  332.     TextMarking = FALSE;
  333.     if (wnd->BlkBegLine > wnd->BlkEndLine)    {
  334.         swap(wnd->BlkBegLine, wnd->BlkEndLine);
  335.         swap(wnd->BlkBegCol, wnd->BlkEndCol);
  336.     }
  337.     if (wnd->BlkBegLine == wnd->BlkEndLine &&
  338.             wnd->BlkBegCol > wnd->BlkEndCol)
  339.         swap(wnd->BlkBegCol, wnd->BlkEndCol);
  340. }
  341. /* ----------- BUTTON_RELEASED Message ---------- */
  342. static int ButtonReleasedMsg(WINDOW wnd)
  343. {
  344.     if (isMultiLine(wnd))    {
  345.         ButtonDown = FALSE;
  346.         if (TextMarking && !(WindowMoving || WindowSizing))  {
  347.             /* release the mouse ouside the edit box */
  348.             SendMessage(NULL, MOUSE_TRAVEL, 0, 0);
  349.             StopMarking(wnd);
  350.             return TRUE;
  351.         }
  352.         else
  353.             PrevY = -1;
  354.     }
  355.     return FALSE;
  356. }
  357. /* ---- Process text block keys for multiline text box ---- */
  358. static void DoMultiLines(WINDOW wnd, int c, PARAM p2)
  359. {
  360.     if (isMultiLine(wnd) && !KeyBoardMarking)    {
  361.         if ((int)p2 & (LEFTSHIFT | RIGHTSHIFT))    {
  362.             switch (c)    {
  363.                 case HOME:
  364.                 case CTRL_HOME:
  365.                 case CTRL_BS:
  366.                 case PGUP:
  367.                 case CTRL_PGUP:
  368.                 case UP:
  369.                 case BS:
  370.                 case END:
  371.                 case CTRL_END:
  372.                 case PGDN:
  373.                 case CTRL_PGDN:
  374.                 case DN:
  375.                 case FWD:
  376.                 case CTRL_FWD:
  377.                     KeyBoardMarking = TextMarking = TRUE;
  378.                     SetAnchor(wnd, wnd->CurrCol, wnd->CurrLine);
  379.                     break;
  380.                 default:
  381.                     break;
  382.             }
  383.         }
  384.     }
  385. }
  386. /* ---------- page/scroll keys ----------- */
  387. static int DoScrolling(WINDOW wnd, int c, PARAM p2)
  388. {
  389.     switch (c)    {
  390.         case PGUP:
  391.         case PGDN:
  392.             if (isMultiLine(wnd))
  393.                 BaseWndProc(EDITBOX, wnd, KEYBOARD, c, p2);
  394.             break;
  395.         case CTRL_PGUP:
  396.         case CTRL_PGDN:
  397.             BaseWndProc(EDITBOX, wnd, KEYBOARD, c, p2);
  398.             break;
  399.         case HOME:
  400.             Home(wnd);
  401.             break;
  402.         case END:
  403.             End(wnd);
  404.             break;
  405.         case CTRL_FWD:
  406.             NextWord(wnd);
  407.             break;
  408.         case CTRL_BS:
  409.             PrevWord(wnd);
  410.             break;
  411.         case CTRL_HOME:
  412.             if (isMultiLine(wnd))    {
  413.                 SendMessage(wnd, SCROLLDOC, TRUE, 0);
  414.                 wnd->CurrLine = 0;
  415.                 wnd->WndRow = 0;
  416.             }
  417.             Home(wnd);
  418.             break;
  419.         case CTRL_END:
  420.             if (isMultiLine(wnd) &&
  421.                     wnd->WndRow+wnd->wtop+1 < wnd->wlines
  422.                         && wnd->wlines > 0) {
  423.                 SendMessage(wnd, SCROLLDOC, FALSE, 0);
  424.                 SetLinePointer(wnd, wnd->wlines-1);
  425.                 wnd->WndRow =
  426.                     min(ClientHeight(wnd)-1, wnd->wlines-1);
  427.                 Home(wnd);
  428.             }
  429.             End(wnd);
  430.             break;
  431.         case UP:
  432.             if (isMultiLine(wnd))
  433.                 Upward(wnd);
  434.             break;
  435.         case DN:
  436.             if (isMultiLine(wnd))
  437.                 Downward(wnd);
  438.             break;
  439.         case FWD:
  440.             Forward(wnd);
  441.             break;
  442.         case BS:
  443.             Backward(wnd);
  444.             break;
  445.         default:
  446.             return FALSE;
  447.     }
  448.     if (!KeyBoardMarking && TextBlockMarked(wnd))    {
  449.         ClearTextBlock(wnd);
  450.         SendMessage(wnd, PAINT, 0, 0);
  451.     }
  452.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  453.     return TRUE;
  454. }
  455. /* -------------- Del key ---------------- */
  456. static void DelKey(WINDOW wnd)
  457. {
  458.     char *currchar = CurrChar;
  459.     int repaint = *currchar == '\n';
  460.     if (TextBlockMarked(wnd))    {
  461.         SendMessage(wnd, COMMAND, ID_DELETETEXT, 0);
  462.         SendMessage(wnd, PAINT, 0, 0);
  463.         return;
  464.     }
  465.     if (isMultiLine(wnd) && *currchar == '\n' && *(currchar+1) == '\0')
  466.         return;
  467.     strcpy(currchar, currchar+1);
  468.     if (repaint)    {
  469.         BuildTextPointers(wnd);
  470.         SendMessage(wnd, PAINT, 0, 0);
  471.     }
  472.     else    {
  473.         ModTextPointers(wnd, wnd->CurrLine+1, -1);
  474.         WriteTextLine(wnd, NULL, wnd->WndRow+wnd->wtop, FALSE);
  475.     }
  476.     wnd->TextChanged = TRUE;
  477. }
  478. /* ------------ Tab key ------------ */
  479. static void TabKey(WINDOW wnd, PARAM p2)
  480. {
  481.     if (isMultiLine(wnd))    {
  482.         int insmd = wnd->InsertMode;
  483.         do  {
  484.             char *cc = CurrChar+1;
  485.             if (!insmd && *cc == '\0')
  486.                 break;
  487.             if (wnd->textlen == wnd->MaxTextLength)
  488.                 break;
  489.             SendMessage(wnd,KEYBOARD,insmd ? ' ' : FWD,0);
  490.         } while (wnd->CurrCol % cfg.Tabs);
  491.     }
  492.     else
  493.         PostMessage(GetParent(wnd), KEYBOARD, '\t', p2);
  494. }
  495. /* ------------ Shift+Tab key ------------ */
  496. static void ShiftTabKey(WINDOW wnd, PARAM p2)
  497. {
  498.     if (isMultiLine(wnd))    {
  499.         do  {
  500.             if (CurrChar == GetText(wnd))
  501.                 break;
  502.             SendMessage(wnd,KEYBOARD,BS,0);
  503.         } while (wnd->CurrCol % cfg.Tabs);
  504.     }
  505.     else
  506.         PostMessage(GetParent(wnd), KEYBOARD, SHIFT_HT, p2);
  507. }
  508. /* --------- All displayable typed keys ------------- */
  509. static void KeyTyped(WINDOW wnd, int c)
  510. {
  511.     char *currchar = CurrChar;
  512.     if ((c != '\n' && c < ' ') || (c & 0x1000))
  513.         /* ---- not recognized by editor --- */
  514.         return;
  515.     if (!isMultiLine(wnd) && TextBlockMarked(wnd))    {
  516.         SendMessage(wnd, CLEARTEXT, 0, 0);
  517.         currchar = CurrChar;
  518.     }
  519.     /* ---- test typing at end of text ---- */
  520.     if (currchar == wnd->text+wnd->MaxTextLength)    {
  521.         /* ---- typing at the end of maximum buffer ---- */
  522.         beep();
  523.         return;
  524.     }
  525.     if (*currchar == '\0')    {
  526.         /* --- insert a newline at end of text --- */
  527.         *currchar = '\n';
  528.         *(currchar+1) = '\0';
  529.         BuildTextPointers(wnd);
  530.     }
  531.     /* --- displayable char or newline --- */
  532.     if (c == '\n' || wnd->InsertMode || *currchar == '\n') {
  533.         /* ------ inserting the keyed character ------ */
  534.         if (wnd->text[wnd->textlen-1] != '\0')    {
  535.             /* --- the current text buffer is full --- */
  536.             if (wnd->textlen == wnd->MaxTextLength)    {
  537.                 /* --- text buffer is at maximum size --- */
  538.                 beep();
  539.                 return;
  540.             }
  541.             /* ---- increase the text buffer size ---- */
  542.             wnd->textlen += GROWLENGTH;
  543.             /* --- but not above maximum size --- */
  544.             if (wnd->textlen > wnd->MaxTextLength)
  545.                 wnd->textlen = wnd->MaxTextLength;
  546.             wnd->text = DFrealloc(wnd->text, wnd->textlen+2);
  547.             wnd->text[wnd->textlen-1] = '\0';
  548.             currchar = CurrChar;
  549.         }
  550.         memmove(currchar+1, currchar, strlen(currchar)+1);
  551.         ModTextPointers(wnd, wnd->CurrLine+1, 1);
  552.         if (isMultiLine(wnd) && wnd->wlines > 1)
  553.             wnd->textwidth = max(wnd->textwidth,
  554.                 (int) (TextLine(wnd, wnd->CurrLine+1)-
  555.                 TextLine(wnd, wnd->CurrLine)));
  556.         else
  557.             wnd->textwidth = max(wnd->textwidth,
  558.                 strlen(wnd->text));
  559.         WriteTextLine(wnd, NULL,
  560.             wnd->wtop+wnd->WndRow, FALSE);
  561.     }
  562.     /* ----- put the char in the buffer ----- */
  563.     *currchar = c;
  564.     wnd->TextChanged = TRUE;
  565.     if (c == '\n')    {
  566.         wnd->wleft = 0;
  567.         BuildTextPointers(wnd);
  568.         End(wnd);
  569.         Forward(wnd);
  570.         SendMessage(wnd, PAINT, 0, 0);
  571.         return;
  572.     }
  573.     /* ---------- test end of window --------- */
  574.     if (WndCol == ClientWidth(wnd)-1)    {
  575.         if (!isMultiLine(wnd))    {
  576.             if (!(currchar == wnd->text+wnd->MaxTextLength-2))
  577.             SendMessage(wnd, HORIZSCROLL, TRUE, 0);
  578.         }
  579.         else    {
  580.             char *cp = currchar;
  581.             while (*cp != ' ' && cp != TextLine(wnd, wnd->CurrLine))
  582.                 --cp;
  583.             if (cp == TextLine(wnd, wnd->CurrLine) ||
  584.                     !wnd->WordWrapMode)
  585.                 SendMessage(wnd, HORIZSCROLL, TRUE, 0);
  586.             else    {
  587.                 int dif = 0;
  588.                 if (c != ' ')    {
  589.                     dif = (int) (currchar - cp);
  590.                     wnd->CurrCol -= dif;
  591.                     SendMessage(wnd, KEYBOARD, DEL, 0);
  592.                     --dif;
  593.                 }
  594.                 SendMessage(wnd, KEYBOARD, '\n', 0);
  595.                 currchar = CurrChar;
  596.                 wnd->CurrCol = dif;
  597.                 if (c == ' ')
  598.                     return;
  599.             }
  600.         }
  601.     }
  602.     /* ------ display the character ------ */
  603.     SetStandardColor(wnd);
  604.     PutWindowChar(wnd, c, WndCol, wnd->WndRow);
  605.     /* ----- advance the pointers ------ */
  606.     wnd->CurrCol++;
  607. }
  608. /* ------------ screen changing key strokes ------------- */
  609. static void DoKeyStroke(WINDOW wnd, int c, PARAM p2)
  610. {
  611.     switch (c)    {
  612.         case RUBOUT:
  613.             if (wnd->CurrCol == 0 && wnd->CurrLine == 0)
  614.                 break;
  615.             SendMessage(wnd, KEYBOARD, BS, 0);
  616.             SendMessage(wnd, KEYBOARD, DEL, 0);
  617.             break;
  618.         case DEL:
  619.             DelKey(wnd);
  620.             break;
  621.         case SHIFT_HT:
  622.             ShiftTabKey(wnd, p2);
  623.             break;
  624.         case '\t':
  625.             TabKey(wnd, p2);
  626.             break;
  627.         case '\r':
  628.             if (!isMultiLine(wnd))    {
  629.                 PostMessage(GetParent(wnd), KEYBOARD, c, p2);
  630.                 break;
  631.             }
  632.             c = '\n';
  633.         default:
  634.             if (TextBlockMarked(wnd))    {
  635.                 SendMessage(wnd, COMMAND, ID_DELETETEXT, 0);
  636.                 SendMessage(wnd, PAINT, 0, 0);
  637.             }
  638.             KeyTyped(wnd, c);
  639.             break;
  640.     }
  641. }
  642. /* ----------- KEYBOARD Message ---------- */
  643. static int KeyboardMsg(WINDOW wnd, PARAM p1, PARAM p2)
  644. {
  645.     int c = (int) p1;
  646.     if (WindowMoving || WindowSizing || ((int)p2 & ALTKEY))
  647.         return FALSE;
  648.     switch (c)    {
  649.         /* --- these keys get processed by lower classes --- */
  650.         case ESC:
  651.         case F1:
  652.         case F2:
  653.         case F3:
  654.         case F4:
  655.         case F5:
  656.         case F6:
  657.         case F7:
  658.         case F8:
  659.         case F9:
  660.         case F10:
  661.         case INS:
  662.         case SHIFT_INS:
  663.         case SHIFT_DEL:
  664.             return FALSE;
  665.         /* --- these keys get processed here --- */
  666.         case CTRL_FWD:
  667.         case CTRL_BS:
  668.         case CTRL_HOME:
  669.         case CTRL_END:
  670.         case CTRL_PGUP:
  671.         case CTRL_PGDN:
  672.             break;
  673.         default:
  674.             /* other ctrl keys get processed by lower classes */
  675.             if ((int)p2 & CTRLKEY)
  676.                 return FALSE;
  677.             /* --- all other keys get processed here --- */
  678.             break;
  679.     }
  680.     DoMultiLines(wnd, c, p2);
  681.     if (DoScrolling(wnd, c, p2))    {
  682.         if (KeyBoardMarking)
  683.             ExtendBlock(wnd, WndCol, wnd->WndRow);
  684.     }
  685.     else if (!TestAttribute(wnd, READONLY))    {
  686.         DoKeyStroke(wnd, c, p2);
  687.         SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  688.     }
  689.     else
  690.         beep();
  691.     return TRUE;
  692. }
  693. /* ----------- SHIFT_CHANGED Message ---------- */
  694. static void ShiftChangedMsg(WINDOW wnd, PARAM p1)
  695. {
  696.     if (!((int)p1 & (LEFTSHIFT | RIGHTSHIFT)) &&
  697.                                    KeyBoardMarking)    {
  698.         StopMarking(wnd);
  699.         KeyBoardMarking = FALSE;
  700.     }
  701. }
  702. /* ----------- ID_DELETETEXT Command ---------- */
  703. static void DeleteTextCmd(WINDOW wnd)
  704. {
  705.     if (TextBlockMarked(wnd))    {
  706.         char *bbl=TextLine(wnd,wnd->BlkBegLine)+wnd->BlkBegCol;
  707.         char *bel=TextLine(wnd,wnd->BlkEndLine)+wnd->BlkEndCol;
  708.         int len = (int) (bel - bbl);
  709.         SaveDeletedText(wnd, bbl, len);
  710.         wnd->TextChanged = TRUE;
  711.         strcpy(bbl, bel);
  712.         wnd->CurrLine = TextLineNumber(wnd, bbl-wnd->BlkBegCol);
  713.         wnd->CurrCol = wnd->BlkBegCol;
  714.         wnd->WndRow = wnd->BlkBegLine - wnd->wtop;
  715.         if (wnd->WndRow < 0)    {
  716.             wnd->wtop = wnd->BlkBegLine;
  717.             wnd->WndRow = 0;
  718.         }
  719.         SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  720.         ClearTextBlock(wnd);
  721.         BuildTextPointers(wnd);
  722.     }
  723. }
  724. /* ----------- ID_CLEAR Command ---------- */
  725. static void ClearCmd(WINDOW wnd)
  726. {
  727.     if (TextBlockMarked(wnd))    {
  728.         char *bbl=TextLine(wnd,wnd->BlkBegLine)+wnd->BlkBegCol;
  729.         char *bel=TextLine(wnd,wnd->BlkEndLine)+wnd->BlkEndCol;
  730.         int len = (int) (bel - bbl);
  731.         SaveDeletedText(wnd, bbl, len);
  732.         wnd->CurrLine = TextLineNumber(wnd, bbl);
  733.         wnd->CurrCol = wnd->BlkBegCol;
  734.         wnd->WndRow = wnd->BlkBegLine - wnd->wtop;
  735.         if (wnd->WndRow < 0)    {
  736.             wnd->WndRow = 0;
  737.             wnd->wtop = wnd->BlkBegLine;
  738.         }
  739.         /* ------ change all text lines in block to \n ----- */
  740.         while (bbl < bel)    {
  741.             char *cp = strchr(bbl, '\n');
  742.             if (cp > bel)
  743.                 cp = bel;
  744.             strcpy(bbl, cp);
  745.             bel -= (int) (cp - bbl);
  746.             bbl++;
  747.         }
  748.         ClearTextBlock(wnd);
  749.         BuildTextPointers(wnd);
  750.         SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  751.         wnd->TextChanged = TRUE;
  752.     }
  753. }
  754. /* ----------- ID_UNDO Command ---------- */
  755. static void UndoCmd(WINDOW wnd)
  756. {
  757.     if (wnd->DeletedText != NULL)    {
  758.         PasteText(wnd, wnd->DeletedText, wnd->DeletedLength);
  759.         free(wnd->DeletedText);
  760.         wnd->DeletedText = NULL;
  761.         wnd->DeletedLength = 0;
  762.         SendMessage(wnd, PAINT, 0, 0);
  763.     }
  764. }
  765. /* ----------- ID_PARAGRAPH Command ---------- */
  766. static void ParagraphCmd(WINDOW wnd)
  767. {
  768.     int bc, fl;
  769.     char *bl, *bbl, *bel, *bb;
  770.  
  771.     ClearTextBlock(wnd);
  772.     /* ---- forming paragraph from cursor position --- */
  773.     fl = wnd->wtop + wnd->WndRow;
  774.     bbl = bel = bl = TextLine(wnd, wnd->CurrLine);
  775.     if ((bc = wnd->CurrCol) >= ClientWidth(wnd))
  776.         bc = 0;
  777.     Home(wnd);
  778.     /* ---- locate the end of the paragraph ---- */
  779.     while (*bel)    {
  780.         int blank = TRUE;
  781.         char *bll = bel;
  782.         /* --- blank line marks end of paragraph --- */
  783.         while (*bel && *bel != '\n')    {
  784.             if (*bel != ' ')
  785.                 blank = FALSE;
  786.             bel++;
  787.         }
  788.         if (blank)    {
  789.             bel = bll;
  790.             break;
  791.         }
  792.         if (*bel)
  793.             bel++;
  794.     }
  795.     if (bel == bbl)    {
  796.         SendMessage(wnd, KEYBOARD, DN, 0);
  797.         return;
  798.     }
  799.     if (*bel == '\0')
  800.         --bel;
  801.     if (*bel == '\n')
  802.         --bel;
  803.     /* --- change all newlines in block to spaces --- */
  804.     while (CurrChar < bel)    {
  805.         if (*CurrChar == '\n')    {
  806.             *CurrChar = ' ';
  807.             wnd->CurrLine++;
  808.             wnd->CurrCol = 0;
  809.         }
  810.         else
  811.             wnd->CurrCol++;
  812.     }
  813.     /* ---- insert newlines at new margin boundaries ---- */
  814.     bb = bbl;
  815.     while (bbl < bel)    {
  816.         bbl++;
  817.         if ((int)(bbl - bb) == ClientWidth(wnd)-1)    {
  818.             while (*bbl != ' ' && bbl > bb)
  819.                 --bbl;
  820.             if (*bbl != ' ')    {
  821.                 bbl = strchr(bbl, ' ');
  822.                 if (bbl == NULL || bbl >= bel)
  823.                     break;
  824.             }
  825.             *bbl = '\n';
  826.             bb = bbl+1;
  827.         }
  828.     }
  829.     BuildTextPointers(wnd);
  830.     /* --- put cursor back at beginning --- */
  831.     wnd->CurrLine = TextLineNumber(wnd, bl);
  832.     wnd->CurrCol = bc;
  833.     if (fl < wnd->wtop)
  834.         wnd->wtop = fl;
  835.     wnd->WndRow = fl - wnd->wtop;
  836.     SendMessage(wnd, PAINT, 0, 0);
  837.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  838.     wnd->TextChanged = TRUE;
  839.     BuildTextPointers(wnd);
  840. }
  841. /* ----------- COMMAND Message ---------- */
  842. static int CommandMsg(WINDOW wnd, PARAM p1)
  843. {
  844.     switch ((int)p1)    {
  845.         case ID_DELETETEXT:
  846.             DeleteTextCmd(wnd);
  847.             return TRUE;
  848.         case ID_CLEAR:
  849.             ClearCmd(wnd);
  850.             return TRUE;
  851.         case ID_UNDO:
  852.             UndoCmd(wnd);
  853.             return TRUE;
  854.         case ID_PARAGRAPH:
  855.             ParagraphCmd(wnd);
  856.             return TRUE;
  857.         default:
  858.             break;
  859.     }
  860.     return FALSE;
  861. }
  862. /* ---------- CLOSE_WINDOW Message ----------- */
  863. static int CloseWindowMsg(WINDOW wnd, PARAM p1, PARAM p2)
  864. {
  865.     int rtn;
  866.     SendMessage(NULL, HIDE_CURSOR, 0, 0);
  867.     if (wnd->DeletedText != NULL)
  868.         free(wnd->DeletedText);
  869.     rtn = BaseWndProc(EDITBOX, wnd, CLOSE_WINDOW, p1, p2);
  870.     if (wnd->text != NULL)    {
  871.         free(wnd->text);
  872.         wnd->text = NULL;
  873.     }
  874.     return rtn;
  875. }
  876. /* ------- Window processing module for EDITBOX class ------ */
  877. int EditBoxProc(WINDOW wnd, MESSAGE msg, PARAM p1, PARAM p2)
  878. {
  879.     int rtn;
  880.     switch (msg)    {
  881.         case CREATE_WINDOW:
  882.             return CreateWindowMsg(wnd);
  883.         case ADDTEXT:
  884.             return AddTextMsg(wnd, p1, p2);
  885.         case SETTEXT:
  886.             return SetTextMsg(wnd, p1);
  887.         case CLEARTEXT:
  888.             return ClearTextMsg(wnd);
  889.         case GETTEXT:
  890.             return GetTextMsg(wnd, p1, p2);
  891.         case SETTEXTLENGTH:
  892.             return SetTextLengthMsg(wnd, (unsigned) p1);
  893.         case KEYBOARD_CURSOR:
  894.             KeyboardCursorMsg(wnd, p1, p2);
  895.             return TRUE;
  896.         case SETFOCUS:
  897.             if (!(int)p1)
  898.                 SendMessage(NULL, HIDE_CURSOR, 0, 0);
  899.         case PAINT:
  900.         case MOVE:
  901.             rtn = BaseWndProc(EDITBOX, wnd, msg, p1, p2);
  902.             SendMessage(wnd,KEYBOARD_CURSOR,WndCol,wnd->WndRow);
  903.             return rtn;
  904.         case SIZE:
  905.             return SizeMsg(wnd, p1, p2);
  906.         case SCROLL:
  907.             return ScrollMsg(wnd, p1);
  908.         case HORIZSCROLL:
  909.             return HorizScrollMsg(wnd, p1);
  910.         case SCROLLPAGE:
  911.             return ScrollPageMsg(wnd, p1);
  912.         case HORIZPAGE:
  913.             return HorizPageMsg(wnd, p1);
  914.         case LEFT_BUTTON:
  915.             if (LeftButtonMsg(wnd, p1, p2))
  916.                 return TRUE;
  917.             break;
  918.         case MOUSE_MOVED:
  919.             if (MouseMovedMsg(wnd, p1, p2))
  920.                 return TRUE;
  921.             break;
  922.         case BUTTON_RELEASED:
  923.             if (ButtonReleasedMsg(wnd))
  924.                 return TRUE;
  925.             break;
  926.         case KEYBOARD:
  927.             if (KeyboardMsg(wnd, p1, p2))
  928.                 return TRUE;
  929.             break;
  930.         case SHIFT_CHANGED:
  931.             ShiftChangedMsg(wnd, p1);
  932.             break;
  933.         case COMMAND:
  934.             if (CommandMsg(wnd, p1))
  935.                 return TRUE;
  936.             break;
  937.         case CLOSE_WINDOW:
  938.             return CloseWindowMsg(wnd, p1, p2);
  939.         default:
  940.             break;
  941.     }
  942.     return BaseWndProc(EDITBOX, wnd, msg, p1, p2);
  943. }
  944. /* ------ save deleted text for the Undo command ------ */
  945. static void SaveDeletedText(WINDOW wnd, char *bbl, int len)
  946. {
  947.     wnd->DeletedLength = len;
  948.     wnd->DeletedText=DFrealloc(wnd->DeletedText,len);
  949.     memmove(wnd->DeletedText, bbl, len);
  950. }
  951. /* ---- cursor right key: right one character position ---- */
  952. static void Forward(WINDOW wnd)
  953. {
  954.     char *cc = CurrChar+1;
  955.     if (*cc == '\0')
  956.         return;
  957.     if (*CurrChar == '\n')    {
  958.         Home(wnd);
  959.         Downward(wnd);
  960.     }
  961.     else    {
  962.         wnd->CurrCol++;
  963.         if (WndCol == ClientWidth(wnd))
  964.             SendMessage(wnd, HORIZSCROLL, TRUE, 0);
  965.     }
  966. }
  967. /* ----- stick the moving cursor to the end of the line ---- */
  968. static void StickEnd(WINDOW wnd)
  969. {
  970.     char *cp = TextLine(wnd, wnd->CurrLine);
  971.     char *cp1 = strchr(cp, '\n');
  972.     int len = cp1 ? (int) (cp1 - cp) : 0;
  973.     wnd->CurrCol = min(len, wnd->CurrCol);
  974.     if (wnd->wleft > wnd->CurrCol)    {
  975.         wnd->wleft = max(0, wnd->CurrCol - 4);
  976.         SendMessage(wnd, PAINT, 0, 0);
  977.     }
  978.     else if (wnd->CurrCol-wnd->wleft >= ClientWidth(wnd))    {
  979.         wnd->wleft = wnd->CurrCol - (ClientWidth(wnd)-1);
  980.         SendMessage(wnd, PAINT, 0, 0);
  981.     }
  982. }
  983. /* --------- cursor down key: down one line --------- */
  984. static void Downward(WINDOW wnd)
  985. {
  986.     if (isMultiLine(wnd) &&
  987.             wnd->WndRow+wnd->wtop+1 < wnd->wlines)  {
  988.         wnd->CurrLine++;
  989.         if (wnd->WndRow == ClientHeight(wnd)-1)
  990.             SendMessage(wnd, SCROLL, TRUE, 0);
  991.         wnd->WndRow++;
  992.         StickEnd(wnd);
  993.     }
  994. }
  995. /* -------- cursor up key: up one line ------------ */
  996. static void Upward(WINDOW wnd)
  997. {
  998.     if (isMultiLine(wnd) && wnd->CurrLine != 0)    {
  999.         --wnd->CurrLine;
  1000.         if (wnd->WndRow == 0)
  1001.             SendMessage(wnd, SCROLL, FALSE, 0);
  1002.         --wnd->WndRow;
  1003.         StickEnd(wnd);
  1004.     }
  1005. }
  1006. /* ---- cursor left key: left one character position ---- */
  1007. static void Backward(WINDOW wnd)
  1008. {
  1009.     if (wnd->CurrCol)    {
  1010.         --wnd->CurrCol;
  1011.         if (wnd->CurrCol < wnd->wleft)
  1012.             SendMessage(wnd, HORIZSCROLL, FALSE, 0);
  1013.     }
  1014.     else if (isMultiLine(wnd) && wnd->CurrLine != 0)    {
  1015.         Upward(wnd);
  1016.         End(wnd);
  1017.     }
  1018. }
  1019. /* -------- End key: to end of line ------- */
  1020. static void End(WINDOW wnd)
  1021. {
  1022.     while (*CurrChar && *CurrChar != '\n')
  1023.         ++wnd->CurrCol;
  1024.     if (WndCol >= ClientWidth(wnd))    {
  1025.         wnd->wleft = wnd->CurrCol - (ClientWidth(wnd)-1);
  1026.         SendMessage(wnd, PAINT, 0, 0);
  1027.     }
  1028. }
  1029. /* -------- Home key: to beginning of line ------- */
  1030. static void Home(WINDOW wnd)
  1031. {
  1032.     wnd->CurrCol = 0;
  1033.     if (wnd->wleft != 0)    {
  1034.         wnd->wleft = 0;
  1035.         SendMessage(wnd, PAINT, 0, 0);
  1036.     }
  1037. }
  1038. /* -- Ctrl+cursor right key: to beginning of next word -- */
  1039. static void NextWord(WINDOW wnd)
  1040. {
  1041.     int savetop = wnd->wtop;
  1042.     int saveleft = wnd->wleft;
  1043.     ClearVisible(wnd);
  1044.     while (!isWhite(*CurrChar))    {
  1045.         char *cc = CurrChar+1;
  1046.         if (*cc == '\0')
  1047.             break;
  1048.         Forward(wnd);
  1049.     }
  1050.     while (isWhite(*CurrChar))    {
  1051.         char *cc = CurrChar+1;
  1052.         if (*cc == '\0')
  1053.             break;
  1054.         Forward(wnd);
  1055.     }
  1056.     SetVisible(wnd);
  1057.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  1058.     if (wnd->wtop != savetop || wnd->wleft != saveleft)
  1059.         SendMessage(wnd, PAINT, 0, 0);
  1060. }
  1061. /* -- Ctrl+cursor left key: to beginning of previous word -- */
  1062. static void PrevWord(WINDOW wnd)
  1063. {
  1064.     int savetop = wnd->wtop;
  1065.     int saveleft = wnd->wleft;
  1066.     ClearVisible(wnd);
  1067.     Backward(wnd);
  1068.     while (isWhite(*CurrChar))    {
  1069.         if (wnd->CurrLine == 0 && wnd->CurrCol == 0)
  1070.             break;
  1071.         Backward(wnd);
  1072.     }
  1073.     while (wnd->CurrCol != 0 && !isWhite(*CurrChar))
  1074.         Backward(wnd);
  1075.     if (isWhite(*CurrChar))
  1076.         Forward(wnd);
  1077.     SetVisible(wnd);
  1078.     if (wnd->wleft != saveleft)
  1079.         if (wnd->CurrCol >= saveleft)
  1080.             if (wnd->CurrCol - saveleft < ClientWidth(wnd))
  1081.                 wnd->wleft = saveleft;
  1082.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  1083.     if (wnd->wtop != savetop || wnd->wleft != saveleft)
  1084.         SendMessage(wnd, PAINT, 0, 0);
  1085. }
  1086. /* ----- modify text pointers from a specified position
  1087.                 by a specified plus or minus amount ----- */
  1088. static void ModTextPointers(WINDOW wnd, int lineno, int var)
  1089. {
  1090.     while (lineno < wnd->wlines)
  1091.         *((wnd->TextPointers) + lineno++) += var;
  1092. }
  1093. /* ----- set anchor point for marking text block ----- */
  1094. static void SetAnchor(WINDOW wnd, int mx, int my)
  1095. {
  1096.     ClearTextBlock(wnd);
  1097.     /* ------ set the anchor ------ */
  1098.     wnd->BlkBegLine = wnd->BlkEndLine = my;
  1099.     wnd->BlkBegCol = wnd->BlkEndCol = mx;
  1100.     SendMessage(wnd, PAINT, 0, 0);
  1101. }
  1102.  
  1103.  
  1104. 
  1105.